#include <stdio.h>
#include<string>
#include<pthread.h>
#include<queue>
#include<iostream>
#include <winsock2.h>

using namespace std;
string serveripstr;
struct RecvInfo
{
	queue<string>*infopool;
	SOCKET RecvSocket;
};
#define NUM_THREADS     5
void *RecvProcess(void *recvinfo)
{
	int bytesRecv = SOCKET_ERROR;
	RecvInfo* recvinfo_ptr = (RecvInfo*)recvinfo;
	char recvbuf[200] = "";
	bytesRecv = recv(recvinfo_ptr->RecvSocket, recvbuf, 200, 0);
	if(bytesRecv == 0)
	{
		cout<<"receive 0 bytes from client!"<<endl;
		//break;
		return NULL;
	}
	if (bytesRecv == SOCKET_ERROR)
	{
		printf("Server: recv() error %ld.\n", WSAGetLastError());
		//break;
		return NULL;
	}
	else
	{
		printf("ReceiverForChatting: recv() is OK.\n");
		printf("ReceiverForChatting: Received data is: \"%s\"\n", recvbuf);
		cout<<recvbuf<<endl;
		recvinfo_ptr->infopool->push(string(recvbuf));
		printf("ReceiverForChatting: Bytes received: %ld.\n", bytesRecv);
		//break;
		return NULL;
	}
}
void *ReceiverForChatting(void *pool)
{
	while(1)
	{
	cout<<"ReceiverForChatting"<<endl;
	queue<string>* pool_ptr = (queue<string>*)pool;

		// Initialize Winsock.
		WSADATA wsaData;
		int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
		if (iResult != NO_ERROR)
			printf("ReceiverForChatting: Error at WSAStartup().\n");
		else
			printf("ReceiverForChatting: WSAStartup() is OK.\n");
	
		// Create a SOCKET for listening for
		// incoming connection requests.
		SOCKET ListenSocket;
		ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (ListenSocket == INVALID_SOCKET)
		{
			printf("ReceiverForChatting: Error at socket(): %ld\n", WSAGetLastError());
			WSACleanup();
			system("pause");
			return 0;
		}
		else
			printf("ReceiverForChatting: socket() is OK.\n");
	
		// The sockaddr_in structure specifies the address family,
		// IP address, and port for the socket that is being bound.
		sockaddr_in service;
		service.sin_family = AF_INET;
		service.sin_addr.s_addr = inet_addr(serveripstr.c_str());
		service.sin_port = htons(54321);
	
		if (bind(ListenSocket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR)
		{
			printf("ReceiverForChatting: bind() failed.\n");
			closesocket(ListenSocket);
			system("pause");
			return 0;
			//continue;

		}
		else
			printf("ReceiverForChatting: bind() is OK.\n");
	
		// Listen for incoming connection requests on the created socket
		if (listen(ListenSocket, 10) == SOCKET_ERROR)
			printf("ReceiverForChatting: Error listening on socket.\n");
		else
			printf("ReceiverForChatting: listen() is OK.\n");
	
		// Create a SOCKET for accepting incoming requests.
		
	
		while(1)
		{
			SOCKET AcceptSocket;
		        printf("ReceiverForChatting: Waiting for client to connect...\n");
			// Accept the connection if any...
			while(1)
			{
				
				AcceptSocket = SOCKET_ERROR;
				while(AcceptSocket == SOCKET_ERROR)
				{
					AcceptSocket = accept(ListenSocket, NULL, NULL);
				}
				printf("ReceiverForChatting: accept() is OK.\n");
				printf("ReceiverForChatting: Client connected...ready for communication.\n");
				break;
			}
			pthread_t *recvinfo_process_thread = new pthread_t;
			RecvInfo* recvinfo = new RecvInfo;
			recvinfo->infopool = pool_ptr;
			recvinfo->RecvSocket = AcceptSocket;
			int rc = 0;
			rc = pthread_create(recvinfo_process_thread, NULL,RecvProcess, (void *)recvinfo);
			if (rc){
				printf("ERROR; return code from pthread_create() is %d\n", rc);
				return NULL;
			}
			//delete recvinfo;
			//delete recvinfo_process_thread;
		}
	}
		WSACleanup();
		cout<<"Receiver quit"<<endl;

	pthread_exit(NULL);

	return NULL;
}

void *SenderForChatting(void *pool)
{
	cout<<"SenderForChattting"<<endl;
	queue<string>* pool_ptr = (queue<string>*)pool;
	char sendbuf[200] = "";
	
	while(1)
	{
		if(!pool_ptr->empty())
		{
			memset(sendbuf,0,strlen(sendbuf));
			strcpy(sendbuf, pool_ptr->front().c_str());
			printf("SenderForChattting: Consume %s", pool_ptr->front().c_str());
			pool_ptr->pop();
			string sendstr = sendbuf;
			cout<<"send string:"<<sendstr<<endl;
			string ipstr = sendstr.substr(0,sendstr.find_first_of(" ",0));
			sendstr.erase(0,sendstr.find_first_of(" ",0)+1);
			cout<<"sendstr :"<<sendstr<<endl;
			cout<<endl;
			for(int i = 0;i < sendstr.length();i++)
			{
				sendbuf[i] = sendstr[i];
				cout<<sendbuf[i]<<" ";
			}
			for(int j = sendstr.length();j < strlen(sendbuf);j++)
				sendbuf[j] = NULL;
			cout<<"IP:"<<ipstr<<endl;
			// Initialize Winsock.
			WSADATA wsaData;
			int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);

			if (iResult != NO_ERROR)
				printf("SenderForChattting: Error at WSAStartup().\n");
			else
				printf("SenderForChattting: WSAStartup() is OK.\n");

			// Create a socket.
			SOCKET m_socket;
			m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

			if (m_socket == INVALID_SOCKET)
			{
				printf("SenderForChattting: socket() - Error at socket(): %ld\n", WSAGetLastError());
				WSACleanup();	
				system("pause");
				return 0;
			}
			else
				printf("SenderForChattting: socket() is OK.\n");

			// Connect to a server.
			sockaddr_in clientService;

			clientService.sin_family = AF_INET;
			clientService.sin_addr.s_addr = inet_addr(ipstr.c_str());
			//clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
			clientService.sin_port = htons(12345);

			if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
			{
				printf("SenderForChattting: connect()1 - Failed to connect.\n");
				WSACleanup();
				system("pause");
				return 0;
			}

			int bytesSent;
			// Sends some test data to server...
			bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0);
			if(bytesSent == SOCKET_ERROR)
				printf("SenderForChattting: send() error %ld.\n", WSAGetLastError());
			else
			{
				printf("SenderForChattting: send() is OK - Bytes sent: %ld\n", bytesSent);
				printf("SenderForChattting: The test string sent: \"%s\"\n", sendbuf);
			}
			cout<<"the process ends"<<endl;
			memset(sendbuf,0,strlen(sendbuf));
			//WSACleanup();
		}
	}
	
	pthread_exit(NULL);

	return NULL;
}

int main (int argc, char *argv[])
{
	pthread_t *receiver_chatting_thread = new pthread_t;
	pthread_t *sender_chatting_thread = new pthread_t;
	pthread_t *receiver_game_thread = new pthread_t;
	pthread_t *sender_game_thread = new pthread_t;


	queue<string>* pool = new queue<string>();
	queue<string>* pool2 = new queue<string>();
	
	int rc1,rc2,rc3,rc4;
	cout<<"Input server ip:"<<endl;
	while(serveripstr.empty())
	{
		cout<<"Server ip is empty! Please reenter it!"<<endl;
	    cin>>serveripstr;
	}

	rc1 = pthread_create(receiver_chatting_thread, NULL, ReceiverForChatting, (void *)pool);
	if (rc1){
		printf("ERROR; return code from pthread_create() is %d\n", rc1);
		return -1;
	}
	
	rc2 = pthread_create(sender_chatting_thread, NULL, SenderForChatting, (void *)pool);
	if (rc2){
		printf("ERROR; return code from pthread_create() is %d\n", rc2);
		return -1;
	}

	/*rc3 = pthread_create(receiver_game_thread,NULL, ReceiverForGame,(void* )pool2);
	if(rc3){
		printf("ERROR; return code from pthread_create() is %d\n", rc3);
		return -1;
	}

	rc4 = pthread_create(sender_game_thread,NULL,SenderForGame,(void*)pool2);
	if(rc4){
		printf("ERROR; return code from pthread_create() is %d\n", rc4);
		return -1;
	}*/

	//delete receiver_thread;
	/*delete sender_thread;*/
	printf("Server: main_thread: exit\n");
	pthread_exit(NULL);
}
